/*
* Copyright 2011 Pavel Kozhin 
*
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed  under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License.
*
* Author: Pavel Kozhin.
*/
package org.etherframework.controller
{
	import flash.errors.IllegalOperationError;
	
	import org.etherframework.common.ICancelable;
	import org.etherframework.common.command.CommandState;
	import org.etherframework.common.command.IProcessingDispatcher;
	import org.etherframework.common.dependency.IEtherChild;
	import org.etherframework.common.dependency.IEtherOwner;
	import org.etherframework.controller.events.CommandProcessingEvent;
	
	import raix.reactive.ICancelable;
	import raix.reactive.IObservable;
	import raix.reactive.Observable;
	
	public class ReactiveCommand extends InitializableCommand implements IReactiveCommand, org.etherframework.common.ICancelable, IEtherChild
	{
		private var _cancelable:raix.reactive.ICancelable;
		private var _owner:IEtherOwner;
		private var _error:Error;
		
		public function observable():IObservable
		{
			throw new IllegalOperationError("This method should be overridden by a subclass.");
		}
		
		public final override function execute():void
		{
			ensureIsInitialized();
			
			ether.commands.dispatchCommandState(
				new CommandState(this, CommandState.EXECUTE));
			
			if (_owner)
				_owner.childAdd(this);
			
			_cancelable = observable().subscribe(null, chainCompleteHandler, chainErrorHandler);
		}
		
		public function cancel():void
		{
			_cancelable.cancel();
		}
		
		public final function owner(value:IEtherOwner):void
		{
			_owner = value;
		}
		
		protected function processing(source:IObservable):IObservable
		{
			return Observable.defer(function():IObservable
				{
					startProcessing();

					return source;
				}).finallyAction(stopProcessing);
		}
		// DONTO NED VALUE!!!!!!!!!!!
		private function chainCompleteHandler(value:* = null):void
		{
			if (_owner)
				_owner.childRemove(this);
			
			// FIXME: Remove command state it.
			ether.commands.dispatchCommandState(
				new CommandState(this, CommandState.COMPLETE));
			
			completeHandler(value);
		}
		
		private function chainErrorHandler(error:Error):void
		{
			_error = error;
			
			if (_owner)
				_owner.childRemove(this);
			
			dispatchError(_error);
			
			// FIXME: Remove command state it.
			ether.commands.dispatchCommandState(
				new CommandState(this, CommandState.COMPLETE, null, _error));
			
			errorHandler(_error);
		}
		
		protected function completeHandler(value:* = null):void
		{
		}
		
		protected function errorHandler(error:Error):void
		{
		}
		
		private function startProcessing():void
		{
			if (this is IProcessingDispatcher)
			{
				ether.dispatch(new CommandProcessingEvent(
					CommandProcessingEvent.START, this as IProcessingDispatcher, null));
			}
		}
		
		private function stopProcessing(error:Object = null):void
		{
			if (this is IProcessingDispatcher)
			{
				ether.dispatch(new CommandProcessingEvent(
					CommandProcessingEvent.STOP, this as IProcessingDispatcher, _error));
			}
		}
	}
}